﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.IO;
using System.Xml;
using System.Text;
using System.Diagnostics;
using EtEnvironment;

namespace RandomSetter
{
    class ValueEnumrator
    {
        public const Int32 BIT_USE_STR = 1;
        public const Int32 BIT_USE_DBL = 2;
        public const Int32 BIT_USE_ERROR = 4;
        public const Int32 BIT_USE_BOOL = 8;
        public const Int32 BITS_USE =
            BIT_USE_STR + BIT_USE_DBL + BIT_USE_ERROR + BIT_USE_BOOL;

        public ValueEnumrator(Int32 iEnumMask)
        {
            m_IntEnumMask = iEnumMask;
            if (m_IntEnumMask <= 0 || BITS_USE < m_IntEnumMask)
            {
                throw new Exception("Error Enum NUMBER" + m_IntEnumMask);
            }

            m_Errors = gVal.GetErrorStrings();
            m_Strings = GetStrings();
            m_Doubles = GetDoubles();
            Reset();
        }

        public void Reset()
        {
            m_IntCurEnumType = 1;
            m_BoolCurValue = false;
            m_CurDoubleIdx = 0;
            m_CurErrorIdx = 0;
            m_CurStringIdx = 0;
        }

        public String GetValue()
        {
            Debug.Assert(m_IntEnumMask > 0);
            while ((m_IntEnumMask & m_IntCurEnumType) == 0)
            {
                m_IntCurEnumType = (m_IntCurEnumType << 1);
                if (m_IntCurEnumType > m_IntEnumMask)
                {
                    m_IntCurEnumType = 1;
                }
            }

            switch (m_IntCurEnumType)
            {
                case BIT_USE_STR: return GetValue_Str();
                case BIT_USE_DBL: return GetValue_Dbl();
                case BIT_USE_ERROR: return GetValue_Error();
                case BIT_USE_BOOL: return GetValue_Bool();
                default: return "";
            }
        }

        public String GetValue_Str()
        {
            Int32 tmp = m_CurStringIdx++;
            m_CurStringIdx %= m_Strings.Length;
            return m_Strings[tmp];
        }

        public String GetValue_Bool()
        {
            Boolean tmp = m_BoolCurValue;
            m_BoolCurValue = !m_BoolCurValue;
            return tmp.ToString();
        }

        private String GetValue_Dbl()
        {
            Int32 tmp = m_CurDoubleIdx++;
            m_CurDoubleIdx %= m_Doubles.Length;
            return m_Doubles[tmp].ToString();
        }

        private String GetValue_Error()
        {
            Int32 tmp = m_CurErrorIdx++;
            m_CurErrorIdx %= m_Errors.Length;
            return m_Errors[tmp];
        }

        private static String[] GetStrings()
        {
            return new String[] {
                "a", "b", "'1", "'2.34454", "'TRUE", "'FALSE", "保佑我能有天越过那片海岸线",
            "到最后还能认得她woduichuanglianWangJIushiYIpian的脸我希望她能比我更好过",
            "'#VALUE!", "以往的每次路过都是晴天",};
        }

        private static Double[] GetDoubles()
        {
            return new Double[] { 0.0, 3.1415, -3.1415, 2.7183, -2.7183, };
        }

        private Boolean m_BoolCurValue;
        private Int32 m_IntCurEnumType;
        private readonly Int32 m_IntEnumMask;

        private readonly Double[] m_Doubles;
        private Int32 m_CurDoubleIdx;

        private readonly String[] m_Errors;
        private Int32 m_CurErrorIdx;

        private readonly String[] m_Strings;
        private Int32 m_CurStringIdx;
    }

    struct CellValueParam
    {
        public CELL cellPos;
        public String strValue;
        public String GetRawStrCell(RangeConverter rgConverter)
        {
            return rgConverter.Cell2String(cellPos, false);
        }
    }

    abstract class TableDataSetterBase
    {
        public TableDataSetterBase(RANGE rg, Int32 nSetType)
        {
            m_rg = rg.ExpandToCells();

            Int32 tmp = gVal.MAX_ROWS_COUNT;
            m_rg.nEndRow = (m_rg.nEndRow + tmp) % tmp;

            tmp = gVal.MAX_COLS_COUNT;
            m_rg.nEndCol = (m_rg.nEndCol + tmp) % tmp;

            m_IntSetType = nSetType;
            m_ValueEnum = new ValueEnumrator(nSetType);

            m_Random = new Random(27128);
        }

        public void AddCellData(Int32 nRow, Int32 nCol, Boolean bForce, List<CellValueParam> valueCells)
        {
            CellValueParam x;
            x.cellPos.nRow = nRow;
            x.cellPos.nCol = nCol;
            x.cellPos.nSheet = m_rg.nBeginSheet;
            x.strValue = m_ValueEnum.GetValue();
            
            Int32 tmp = valueCells.Count / m_IntLimit;
            if (bForce || m_Random.Next(0, tmp+1) == tmp)
            {
                valueCells.Add(x);
            }
        }

        protected Boolean IsEqualRowBound(Int32 iValue, ref RANGE rg)
        {
            Debug.Assert(0 <= iValue);
            Int32 nx = (gVal.MAX_ROWS_COUNT + rg.nEndRow) % gVal.MAX_ROWS_COUNT;
            return rg.nBeginRow == iValue || iValue == nx;
        }

        protected Boolean IsEqualColBound(Int32 iValue, ref RANGE rg)
        {
            Debug.Assert(0 <= iValue);
            Int32 nx = (gVal.MAX_COLS_COUNT + rg.nEndCol) % gVal.MAX_ROWS_COUNT;
            return rg.nBeginCol == iValue || iValue == nx;
        }

        public abstract bool Check();
        public abstract void Do(List<CellValueParam> valueCells);

        protected RANGE m_rg;
        protected Int32 m_IntSetType;
        protected ValueEnumrator m_ValueEnum;
        protected Random m_Random;
        const Int32 m_IntLimit = 2048;

        static public TableDataSetterBase[] GainClasses(RANGE rg, Int32 nSetType)
        {
            return new TableDataSetterBase[]{
                    new TableDataSetter_Top_1(rg, nSetType),
                    new TableDataSetter_Top_2(rg, nSetType),
                    new TableDataSetter_Bottom_1(rg, nSetType),
                    new TableDataSetter_Bottom_2(rg, nSetType),
                    new TableDataSetter_Left_1(rg, nSetType),
                    new TableDataSetter_Left_2(rg, nSetType),
                    new TableDataSetter_Right_1(rg, nSetType),
                    new TableDataSetter_Right_2(rg, nSetType),
                    new TableDataSetter_TopLeft_1(rg, nSetType),
                    new TableDataSetter_TopLeft_2(rg, nSetType),
                    new TableDataSetter_BottomLeft_1(rg, nSetType),
                    new TableDataSetter_BottomLeft_2(rg, nSetType),
                    new TableDataSetter_TopRight_1(rg, nSetType),
                    new TableDataSetter_TopRight_2(rg, nSetType),
                    new TableDataSetter_BottomRight_1(rg, nSetType),
                    new TableDataSetter_BottomRight_2(rg, nSetType),
                    new TableDataSetter_Whole(rg, nSetType),
                    new TableDataSetter_None(rg, nSetType),
                };
        }
    }

    //todo 实现注释掉的派生类
    internal class TableDataSetter_Top_1 : TableDataSetterBase
    {
        public TableDataSetter_Top_1(RANGE rg, Int32 nSetType)
            : base(rg, nSetType)
        {
        }

        public override bool Check()
        {
            return m_rg.nBeginRow < m_rg.nEndRow;
        }

        public override void Do(List<CellValueParam> valueCells)
        {
            for (Int32 nCol = m_rg.nBeginCol; nCol <= m_rg.nEndCol; ++nCol)
            {
                Boolean bForce = IsEqualColBound(nCol, ref m_rg);
                AddCellData(m_rg.nBeginRow, nCol, bForce, valueCells);
            }
        }
    }

    internal class TableDataSetter_Top_2 : TableDataSetterBase
    {
        public TableDataSetter_Top_2(RANGE rg, Int32 nSetType)
            : base(rg, nSetType)
        {
        }

        public override bool Check()
        {
            return (m_rg.nBeginRow + 1) < m_rg.nEndRow;
        }

        public override void Do(List<CellValueParam> valueCells)
        {
            for (Int32 nCol = m_rg.nBeginCol; nCol <= m_rg.nEndCol; ++nCol)
            {
                Boolean bForce = IsEqualColBound(nCol, ref m_rg);
                AddCellData(m_rg.nBeginRow, nCol, bForce, valueCells);
                AddCellData(m_rg.nBeginRow + 1, nCol, bForce, valueCells);
            }
        }
    }

    internal class TableDataSetter_Bottom_1 : TableDataSetterBase
    {
        public TableDataSetter_Bottom_1(RANGE rg, Int32 nSetType)
            : base(rg, nSetType)
        {
        }

        public override bool Check()
        {
            return m_rg.nBeginRow < m_rg.nEndRow;
        }

        public override void Do(List<CellValueParam> valueCells)
        {
            for (Int32 nCol = m_rg.nBeginCol; nCol <= m_rg.nEndCol; ++nCol)
            {
                Boolean bForce = IsEqualColBound(nCol, ref m_rg);
                AddCellData(m_rg.nEndRow, nCol, bForce, valueCells);
            }
        }
    }

    internal class TableDataSetter_Bottom_2 : TableDataSetterBase
    {
        public TableDataSetter_Bottom_2(RANGE rg, Int32 nSetType)
            : base(rg, nSetType)
        {
        }

        public override bool Check()
        {
            return (m_rg.nBeginRow + 1) < m_rg.nEndRow;
        }

        public override void Do(List<CellValueParam> valueCells)
        {
            for (Int32 nCol = m_rg.nBeginCol; nCol <= m_rg.nEndCol; ++nCol)
            {
                Boolean bForce = (m_rg.nBeginCol == nCol || nCol == m_rg.nEndCol);
                AddCellData(m_rg.nEndRow, nCol, bForce, valueCells);
                AddCellData(m_rg.nEndRow - 1, nCol, bForce, valueCells);
            }
        }
    }

    internal class TableDataSetter_Left_1 : TableDataSetterBase
    {
        public TableDataSetter_Left_1(RANGE rg, Int32 nSetType)
            : base(rg, nSetType)
        {
        }

        public override bool Check()
        {
            return m_rg.nBeginCol < m_rg.nEndCol;
        }

        public override void Do(List<CellValueParam> valueCells)
        {
            for (Int32 nRow = m_rg.nBeginRow; nRow <= m_rg.nEndRow; ++nRow)
            {
                Boolean bForce = IsEqualRowBound(nRow, ref m_rg);
                AddCellData(nRow, m_rg.nBeginCol, bForce, valueCells);
            }
        }
    }

    internal class TableDataSetter_Left_2 : TableDataSetterBase
    {
        public TableDataSetter_Left_2(RANGE rg, Int32 nSetType)
            : base(rg, nSetType)
        {
        }

        public override bool Check()
        {
            return (m_rg.nBeginCol + 1) < m_rg.nEndCol;
        }

        public override void Do(List<CellValueParam> valueCells)
        {
            for (Int32 nRow = m_rg.nBeginRow; nRow <= m_rg.nEndRow; ++nRow)
            {
                Boolean bForce = IsEqualRowBound(nRow, ref m_rg);
                AddCellData(nRow, m_rg.nBeginCol, bForce, valueCells);
                AddCellData(nRow, m_rg.nBeginCol + 1, bForce, valueCells);
            }
        }
    }

    internal class TableDataSetter_Right_1 : TableDataSetterBase
    {
        public TableDataSetter_Right_1(RANGE rg, Int32 nSetType)
            : base(rg, nSetType)
        {
        }

        public override bool Check()
        {
            return m_rg.nBeginCol < m_rg.nEndCol;
        }

        public override void Do(List<CellValueParam> valueCells)
        {
            for (Int32 nRow = m_rg.nBeginRow; nRow <= m_rg.nEndRow; ++nRow)
            {
                Boolean bForce = IsEqualRowBound(nRow, ref m_rg);
                AddCellData(nRow, m_rg.nEndCol, bForce, valueCells);
            }
        }
    }

    internal class TableDataSetter_Right_2 : TableDataSetterBase
    {
        public TableDataSetter_Right_2(RANGE rg, Int32 nSetType)
            : base(rg, nSetType)
        {
        }

        public override bool Check()
        {
            return (m_rg.nBeginCol + 1) < m_rg.nEndCol;
        }

        public override void Do(List<CellValueParam> valueCells)
        {
            for (Int32 nRow = m_rg.nBeginRow; nRow <= m_rg.nEndRow; ++nRow)
            {
                Boolean bForce = IsEqualRowBound(nRow, ref m_rg);
                AddCellData(nRow, m_rg.nEndCol, bForce, valueCells);
                AddCellData(nRow, m_rg.nEndCol - 1, bForce, valueCells);
            }
        }
    }

    internal class TableDataSetter_TopLeft_1 : TableDataSetterBase
    {
        public TableDataSetter_TopLeft_1(RANGE rg, Int32 nSetType)
            : base(rg, nSetType)
        {
        }

        public override bool Check()
        {
            return m_rg.nBeginCol < m_rg.nEndCol && m_rg.nBeginRow < m_rg.nEndRow;
        }

        public override void Do(List<CellValueParam> valueCells)
        {
            AddCellData(m_rg.nBeginRow, m_rg.nBeginCol, true, valueCells);
        }
    }

    internal class TableDataSetter_TopLeft_2 : TableDataSetterBase
    {
        public TableDataSetter_TopLeft_2(RANGE rg, Int32 nSetType)
            : base(rg, nSetType)
        {
        }

        public override bool Check()
        {
            return (m_rg.nBeginCol + 1) < m_rg.nEndCol && (m_rg.nBeginRow + 1) < m_rg.nEndRow;
        }

        public override void Do(List<CellValueParam> valueCells)
        {
            AddCellData(m_rg.nBeginRow, m_rg.nBeginCol, true, valueCells);
            AddCellData(m_rg.nBeginRow + 1, m_rg.nBeginCol, true, valueCells);
            AddCellData(m_rg.nBeginRow, m_rg.nBeginCol + 1, true, valueCells);
            AddCellData(m_rg.nBeginRow + 1, m_rg.nBeginCol + 1, true, valueCells);
        }
    }
    internal class TableDataSetter_BottomLeft_1 : TableDataSetterBase
    {
        public TableDataSetter_BottomLeft_1(RANGE rg, Int32 nSetType)
            : base(rg, nSetType)
        {
        }

        public override bool Check()
        {
            return m_rg.nBeginCol < m_rg.nEndCol && m_rg.nBeginRow < m_rg.nEndRow;
        }

        public override void Do(List<CellValueParam> valueCells)
        {
            AddCellData(m_rg.nEndRow, m_rg.nBeginCol, true, valueCells);
        }
    }

    internal class TableDataSetter_BottomLeft_2 : TableDataSetterBase
    {
        public TableDataSetter_BottomLeft_2(RANGE rg, Int32 nSetType)
            : base(rg, nSetType)
        {
        }

        public override bool Check()
        {
            return (m_rg.nBeginCol + 1) < m_rg.nEndCol && (m_rg.nBeginRow + 1) < m_rg.nEndRow;
        }

        public override void Do(List<CellValueParam> valueCells)
        {
            AddCellData(m_rg.nEndRow, m_rg.nBeginCol, true, valueCells);
            AddCellData(m_rg.nEndRow - 1, m_rg.nBeginCol, true, valueCells);
            AddCellData(m_rg.nEndRow, m_rg.nBeginCol + 1, true, valueCells);
            AddCellData(m_rg.nEndRow - 1, m_rg.nBeginCol + 1, true, valueCells);
        }
    }

    internal class TableDataSetter_TopRight_1 : TableDataSetterBase
    {
        public TableDataSetter_TopRight_1(RANGE rg, Int32 nSetType)
            : base(rg, nSetType)
        {
        }

        public override bool Check()
        {
            return (m_rg.nBeginCol) < m_rg.nEndCol && (m_rg.nBeginRow) < m_rg.nEndRow;
        }

        public override void Do(List<CellValueParam> valueCells)
        {
            AddCellData(m_rg.nBeginRow, m_rg.nEndCol, true, valueCells);
        }
    }

    internal class TableDataSetter_TopRight_2 : TableDataSetterBase
    {
        public TableDataSetter_TopRight_2(RANGE rg, Int32 nSetType)
            : base(rg, nSetType)
        {
        }

        public override bool Check()
        {
            return (m_rg.nBeginCol+1) < m_rg.nEndCol && (m_rg.nBeginRow+1) < m_rg.nEndRow;
        }

        public override void Do(List<CellValueParam> valueCells)
        {
            AddCellData(m_rg.nBeginRow, m_rg.nEndCol, true, valueCells);
            AddCellData(m_rg.nBeginRow + 1, m_rg.nEndCol, true, valueCells);
            AddCellData(m_rg.nBeginRow, m_rg.nEndCol - 1, true, valueCells);
            AddCellData(m_rg.nBeginRow + 1, m_rg.nEndCol - 1, true, valueCells);
        }
    }

    internal class TableDataSetter_BottomRight_1 : TableDataSetterBase
    {
        public TableDataSetter_BottomRight_1(RANGE rg, Int32 nSetType)
            : base(rg, nSetType)
        {
        }

        public override bool Check()
        {
            return (m_rg.nBeginCol) < m_rg.nEndCol && (m_rg.nBeginRow) < m_rg.nEndRow;
        }

        public override void Do(List<CellValueParam> valueCells)
        {
            AddCellData(m_rg.nEndRow, m_rg.nEndCol, true, valueCells);
        }
    }

    internal class TableDataSetter_BottomRight_2 : TableDataSetterBase
    {
        public TableDataSetter_BottomRight_2(RANGE rg, Int32 nSetType)
            : base(rg, nSetType)
        {
        }

        public override bool Check()
        {
            return (m_rg.nBeginCol + 1) < m_rg.nEndCol && (m_rg.nBeginRow + 1) < m_rg.nEndRow;
        }

        public override void Do(List<CellValueParam> valueCells)
        {
            AddCellData(m_rg.nEndRow, m_rg.nEndCol, true, valueCells);
            AddCellData(m_rg.nEndRow - 1, m_rg.nEndCol, true, valueCells);
            AddCellData(m_rg.nEndRow, m_rg.nEndCol - 1, true, valueCells);
            AddCellData(m_rg.nEndRow - 1, m_rg.nEndCol - 1, true, valueCells);
        }
    }

    internal class TableDataSetter_Whole : TableDataSetterBase
    {
        public TableDataSetter_Whole(RANGE rg, Int32 nSetType)
            : base(rg, nSetType)
        {
        }

        public override bool Check()
        {
            return (m_rg.nEndCol - m_rg.nBeginCol + 1) *
                (m_rg.nEndRow - m_rg.nBeginRow + 1) <=
                (gVal.MAX_ROWS_COUNT * 2);
        }

        public override void Do(List<CellValueParam> valueCells)
        {
            for (Int32 nRow = m_rg.nBeginRow; nRow <= m_rg.nEndRow; ++nRow)
            {
                for (Int32 nCol = m_rg.nBeginCol; nCol <= m_rg.nEndCol; ++nCol)
                {
                    Boolean bForce =
                        IsEqualColBound(nCol, ref m_rg) &&
                        IsEqualRowBound(nRow, ref m_rg);
                    AddCellData(nRow, nCol, bForce, valueCells);
                }
            }
        }
    }

    internal class TableDataSetter_None : TableDataSetterBase
    {
        public TableDataSetter_None(RANGE rg, Int32 nSetType)
            : base(rg, nSetType)
        {
        }

        public override bool Check()
        {
            return true;
        }

        public override void Do(List<CellValueParam> valueCells)
        {
        }
    }
}
